package com.cqvip.innocence.framework.config.mybatisplus;

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.core.MybatisConfiguration;
import com.baomidou.mybatisplus.core.config.GlobalConfig;
import com.baomidou.mybatisplus.core.incrementer.IKeyGenerator;
import com.baomidou.mybatisplus.extension.incrementer.*;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.BlockAttackInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import org.apache.ibatis.logging.stdout.StdOutImpl;
import org.apache.ibatis.session.SqlSessionFactory;
import org.jetbrains.annotations.NotNull;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.aop.interceptor.PerformanceMonitorInterceptor;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;

import javax.sql.DataSource;

/**
 * @author 01
 * @date 2022-06-23 11:27
 */
@Configuration
@MapperScan(basePackages = "com.cqvip.innocence.**.slaveMapper", sqlSessionTemplateRef = "slaveSqlSessionTemplate")
public class MybatisPlusSlaveConfig {
    @Value("${spring.datasource.dynamic.datasource.slave.url}")
    private String url;

    private DbType getDbType(@NotNull String str) {
        if (!str.contains(":mysql:") && !str.contains(":cobar:")) {
            if (str.contains(":oracle:")) {
                return DbType.ORACLE;
            } else if (str.contains(":postgresql:")) {
                return DbType.POSTGRE_SQL;
            } else if (str.contains(":sqlserver:")) {
                return DbType.SQL_SERVER;
            } else if (str.contains(":db2:")) {
                return DbType.DB2;
            } else if (str.contains(":mariadb:")) {
                return DbType.MARIADB;
            } else if (str.contains(":sqlite:")) {
                return DbType.SQLITE;
            } else if (str.contains(":h2:")) {
                return DbType.H2;
            } else if (!str.contains(":kingbase:") && !str.contains(":kingbase8:")) {
                if (str.contains(":dm:")) {
                    return DbType.DM;
                } else if (str.contains(":zenith:")) {
                    return DbType.GAUSS;
                } else if (str.contains(":oscar:")) {
                    return DbType.OSCAR;
                } else if (str.contains(":firebird:")) {
                    return DbType.FIREBIRD;
                } else if (str.contains(":xugu:")) {
                    return DbType.XU_GU;
                } else {
                    return str.contains(":clickhouse:") ? DbType.CLICK_HOUSE : DbType.OTHER;
                }
            } else {
                return DbType.KINGBASE_ES;
            }
        } else {
            return DbType.MYSQL;
        }
    }

    /**
     * mybatis-plus SQL执行效率插件【生产环境可以关闭】
     *
     * @return PerformanceMonitorInterceptor
     */
    @Bean(name = "slavePerformanceMonitorInterceptor")
    public PerformanceMonitorInterceptor performanceMonitorInterceptor() {
        return new PerformanceMonitorInterceptor();
    }

    /**
     * 分页插件
     *
     * @return PaginationInterceptor
     */
    @Bean(name = "slaveMybatisPlusInterceptor")
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        PaginationInnerInterceptor innerInterceptor = new PaginationInnerInterceptor(getDbType(url));
        innerInterceptor.setOverflow(false);
        innerInterceptor.setMaxLimit(-1L);
        interceptor.addInnerInterceptor(innerInterceptor);
        interceptor.addInnerInterceptor(new BlockAttackInnerInterceptor());
        return interceptor;
    }

    /**
     * 使用内置的主键生成策略
     *
     * @return IKeyGenerator
     */
    @Bean("slaveIKeyGenerator")
    public IKeyGenerator iKeyGenerator() {
        DbType dbType = getDbType(url);
        if (dbType.getDb().equals(DbType.DB2.getDb())) {
            return new DB2KeyGenerator();
        } else if (dbType.getDb().equals(DbType.H2.getDb())) {
            return new H2KeyGenerator();
        } else if (dbType.getDb().equals(DbType.POSTGRE_SQL.getDb())) {
            return new PostgreKeyGenerator();
        } else if (dbType.getDb().equals(DbType.KINGBASE_ES.getDb())) {
            return new KingbaseKeyGenerator();
        } else if (dbType.getDb().equals(DbType.ORACLE.getDb()) || dbType.getDb().equals(DbType.DM.getDb())) {
            return new OracleKeyGenerator();
        } else {
            return null;
        }
    }

    /**
     * 使用MyMetaObjectHandler配置的自动字段填充
     *
     * @return GlobalConfig
     */
    @Bean(name = "slaveGlobalConfig")
    public GlobalConfig globalConfig() {
        GlobalConfig globalConfig = new GlobalConfig();
        globalConfig.setMetaObjectHandler(new MyMetaObjectHandler());
        return globalConfig;
    }

    @Value("${mybatis-plus.mapper-locations}")
    private String mapperLocations;

    //数据源 slave数据源
    @Bean("slaveSqlSessionFactory")
    public SqlSessionFactory slaveSqlSessionFactory(@Qualifier("slaveDataSource") DataSource dataSource,
                                                    @Qualifier("slaveGlobalConfig") GlobalConfig globalConfig,
                                                    @Qualifier("slaveMybatisPlusInterceptor") MybatisPlusInterceptor interceptor) throws Exception {
        MybatisSqlSessionFactoryBean sqlSessionFactory = new MybatisSqlSessionFactoryBean();
        MybatisConfiguration configuration = new MybatisConfiguration();
        configuration.addInterceptor(interceptor);
        //枚举处理
//        configuration.getTypeHandlerRegistry().setDefaultEnumTypeHandler(EnumOrdinalTypeHandler.class);

        //打印sql
        configuration.setLogImpl(StdOutImpl.class);
        sqlSessionFactory.setConfiguration(configuration);
        sqlSessionFactory.setDataSource(dataSource);
        //GlobalConfig globalConfig  = new GlobalConfig();
        globalConfig.setMetaObjectHandler(new MyMetaObjectHandler());
        sqlSessionFactory.setGlobalConfig(globalConfig);
        sqlSessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver().
                getResources(mapperLocations));
        return sqlSessionFactory.getObject();
    }

    @Bean(name = "slaveTransactionManager")
    public DataSourceTransactionManager slaveTransactionManager(@Qualifier("slaveDataSource") DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }

    @Bean(name = "slaveSqlSessionTemplate")
    public SqlSessionTemplate slaveSqlSessionTemplate(@Qualifier("slaveSqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
        return new SqlSessionTemplate(sqlSessionFactory);
    }


}
